<div class="tutorial-bundle" data-metadata-json='{"programKind": "per-method", "difficulty": "advanced", "groupedProjectAssets": [{"name": "Boing player bats", "assets": ["player-bat-smile.png", "player-bat-wince.png"]}, {"name": "Boing robot bats", "assets": ["robot-bat-smile.png", "robot-bat-wince.png"]}]}' data-tip-sha1="357692c9c16e76ed3021bfff7679fd8b9811422a"><div class="front-matter" data-complete-code-text='import pytch
import random
import math


class Stage(pytch.Stage):
    Backdrops = ["court.png"]


class PlayerBat(pytch.Sprite):
    Costumes = ["player-bat-smile.png", "player-bat-wince.png"]

    @pytch.when_green_flag_clicked
    def play(self):
        self.go_to_xy(-212, 0)

        while True:
            if pytch.key_pressed("w") and self.y_position &lt; 112:
                self.change_y(3)
            if pytch.key_pressed("s") and self.y_position &gt; -112:
                self.change_y(-3)

    @pytch.when_I_receive("player-hit")
    def flash_briefly(self):
        self.switch_costume("player-bat-wince.png")
        pytch.wait_seconds(0.3)
        self.switch_costume("player-bat-smile.png")


class RobotBat(pytch.Sprite):
    Costumes = ["robot-bat-smile.png", "robot-bat-wince.png"]

    @pytch.when_green_flag_clicked
    def play(self):
        self.go_to_xy(212, 0)

        while True:
            target_y = Ball.the_original().y_position
            if target_y &gt; 112:
                target_y = 112
            if target_y &lt; -112:
                target_y = -112
            self.set_y(target_y)

    @pytch.when_I_receive("robot-hit")
    def flash_briefly(self):
        self.switch_costume("robot-bat-wince.png")
        pytch.wait_seconds(0.3)
        self.switch_costume("robot-bat-smile.png")


class Ball(pytch.Sprite):
    Costumes = ["yellow-ball.png"]

    @pytch.when_green_flag_clicked
    def play(self):
        self.go_to_xy(0, 0)

        x_velocity = 3
        y_velocity = 0
        while True:
            self.change_x(x_velocity)

            if self.x_position &gt; 195:
                self.change_x(-x_velocity)
                x_velocity = -x_velocity
                y_velocity = random.randint(-4, 4)
                pytch.broadcast("robot-hit")

            if self.x_position &lt; -195:
                if self.touching(PlayerBat):
                    self.change_x(-x_velocity)
                    x_velocity = -x_velocity
                    y_velocity = random.randint(-4, 4)
                    pytch.broadcast("player-hit")
                else:
                    self.hide()
                    break

            self.change_y(y_velocity)

            if self.y_position &gt; 150 or self.y_position &lt; -150:
                self.change_y(-y_velocity)
                y_velocity = -y_velocity
' data-initial-code-text='import pytch
import random
import math


class Stage(pytch.Stage):
    Backdrops = ["solid-white.png"]
'><h1>Boing: Make a Pong-like game</h1><p>In this tutorial we will make a version of the classic game
<a href="https://en.wikipedia.org/wiki/Pong">Pong</a>.</p></div><div class="chapter-content"><h2>Set up the playing area</h2><p>The game needs a better backdrop than the plain one it has by default.
Pytch’s media library has an image for the court we can use.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add the “court” image as a new Backdrop for the stage.  You can find
it in the media library.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-medialib-appearances-entry", "actor": {"kind": "stage"}, "displayIdentifier": "court.png", "nItems": 1}' data-slug="add-table-backdrop"></div>
</div></div><p>You don’t need the default plain backdrop any more.</p><div class="learner-task"><div class="learner-task-intro">
<p>Delete the plain white backdrop from the stage.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "delete-appearance", "actor": {"kind": "stage"}, "appearanceFilename": "solid-white.png"}' data-slug="remove-default-backdrop"></div>
</div></div></div><div class="chapter-content"><h2>Add the player’s bat</h2><p>Next, the game needs a bat for the player to control.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a sprite called <code>PlayerBat</code> to your game.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-sprite", "name": "PlayerBat"}' data-slug="add-PlayerBat-sprite"></div>
</div></div><p>The sprite needs a costume.  There is a bundle of two costumes in
Pytch’s media library, one “smiling” and one “wincing”.  We will
use the “smiling” one now, and the “wincing” one later on in this
tutorial.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add the “Boing player bats” bundle of images as Costumes for the
<code>PlayerBat</code> sprite.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-medialib-appearances-entry", "actor": {"kind": "sprite", "name": "PlayerBat"}, "displayIdentifier": "Boing player bats", "nItems": 2}' data-slug="add-PlayerBat-costumes"></div>
</div></div><div class="learner-task"><div class="learner-task-intro">
<p>Test your game!  You should see the player’s bat in the middle of the
court background.</p>
</div></div></div><div class="chapter-content"><h2>Let the player control their bat</h2><p>The player bat needs some scripts to control its behaviour.</p><p>When the green flag is clicked, the player’s bat needs to go to its
starting position at the left of the court.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a “when green flag clicked” script to the <code>PlayerBat</code> sprite.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "codeText": ""}' data-slug="add-empty-PlayerBat-play-script"></div>
</div></div><p>You can use the “Show coordinates” helper to check that <code>(-212, 0)</code> is
a reasonable choice for the player’s bat’s starting position.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a line of code to the script which moves the player’s bat to the
position with coordinates <code>(-212, 0)</code>.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "", "newCodeText": "self.go_to_xy(-212, 0)"}' data-slug="centre-PlayerBat-on-start"></div>
</div></div><p>Once the game has started, the player needs to be able to move the
bat, either up or down.</p><h3>Moving up</h3><p>The program should continually check whether the player is
pressing the <code>w</code> key to move up.  If they are, your code needs to
change the bat’s <code>y</code> coordinate.</p><p>In Scratch, this would look like:</p><pre><code class="language-scratch">forever
  if &lt;key (w v) pressed&gt; then
    change y by (3)
</code></pre><div class="learner-task"><div class="learner-task-intro">
<p>Work out the Python code which does this job.  You can use the help
<code>(?)</code> to find how to do “forever”, “if”, “key pressed”, and “change y”
in Pytch.</p>
<p>You’ll also need to know how to put Python code “inside” things like
“forever” and “if”.  There are examples in the help.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(-212, 0)", "newCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\"):\n        self.change_y(3)"}' data-slug="move-PlayerBat-up-with-W"></div>
</div></div><h3>Moving down</h3><p>This is similar.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add similar lines of code, to make the player’s bat move down when the
<code>s</code> key is pressed.</p>
</div><div class="learner-task-help">
<p><strong>Important:</strong> You do <strong>not</strong> need another <code>while True</code> loop.  The new
code can go “inside” the same <code>while True</code> loop you already have.</p>
</div><div class="learner-task-help">
<p>You can copy and paste the two lines of code you already have, then
change the copy, if you think that will save time.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\"):\n        self.change_y(3)", "newCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\"):\n        self.change_y(3)\n    if pytch.key_pressed(\"s\"):\n        self.change_y(-3)"}' data-slug="move-PlayerBat-down-with-S"></div>
</div></div><h3>Test it!</h3><div class="learner-task"><div class="learner-task-intro">
<p>Try your game.  Hold down the <code>w</code> key and check the bat moves up.
Hold down the <code>s</code> key and check it moves down.</p>
<p><strong>There is a bug — what is it?</strong></p>
</div><div class="learner-task-help">
<p>The player can move the bat right off the top or bottom of the court.</p>
</div></div><h3>Staying on the court</h3><p>If you play the game now, you’ll see a bug.  You can move the bat
right off the top or bottom of the court.  To stop this, you need to
add checks to your code.</p><p>At the moment, the code only checks whether the player is pressing <code>w</code>
before deciding it should move the bat up.  But there are <em>two</em> things
that <em>both</em> must be true for the bat to move up:</p><ul>
<li>The <code>w</code> key must be pressed.</li>
<li>The bat must be low enough that moving up is allowed.</li>
</ul><div class="learner-task"><div class="learner-task-intro">
<p>Extend the</p>
<pre><code class="language-python-expression">pytch.key_pressed("w")
</code></pre>
<p>test in your code to <em>also</em> test whether the bat is low enough.</p>
</div><div class="learner-task-help">
<p>To test whether the bat is low enough, you can ask whether its <em>y</em>
coordinate is less than some fixed value: you can experiment to check
that <code>112</code> works for this.</p>
</div><div class="learner-task-help">
<p>The expression</p>
<pre><code class="language-python-expression">self.y_position &lt; 112
</code></pre>
<p>will test whether the bat is low enough.</p>
</div><div class="learner-task-help">
<p>You can join these tests together with Python’s <code>and</code> operator.  This
works the same as Scratch’s</p>
<pre><code class="language-scratch">&lt; &lt;&gt; and &lt;&gt; &gt;
</code></pre>
<p>block.</p>
</div><div class="learner-task-help">
<p>The new test expression for your <code>if</code> statement is</p>
<pre><code class="language-python-expression">pytch.key_pressed("w") and self.y_position &lt; 112
</code></pre>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\"):\n        self.change_y(3)\n    if pytch.key_pressed(\"s\"):\n        self.change_y(-3)", "newCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\") and self.y_position &lt; 112:\n        self.change_y(3)\n    if pytch.key_pressed(\"s\"):\n        self.change_y(-3)"}' data-slug="clamp-PlayerBat-y-high"></div>
</div></div><p>The same problem happens for moving down.  The player bat can go right
off the bottom of the court.</p><div class="learner-task"><div class="learner-task-intro">
<p>Make a similar change to the “move down” code.</p>
</div><div class="learner-task-help">
<p>The extra part of the test in the <code>if</code> statement this time will be to
test whether the <em>y</em> coordinate is <em>greater than</em> some fixed value.
Everything is symmetrical up/down, so <code>-112</code> will work for the value
to compare the <em>y</em> coordinate against.</p>
</div><div class="learner-task-help">
<p>The expression</p>
<pre><code class="language-python-expression">self.y_position &gt; -112
</code></pre>
<p>will test whether the bat is high enough.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\") and self.y_position &lt; 112:\n        self.change_y(3)\n    if pytch.key_pressed(\"s\"):\n        self.change_y(-3)", "newCodeText": "self.go_to_xy(-212, 0)\n\nwhile True:\n    if pytch.key_pressed(\"w\") and self.y_position &lt; 112:\n        self.change_y(3)\n    if pytch.key_pressed(\"s\") and self.y_position &gt; -112:\n        self.change_y(-3)"}' data-slug="clamp-PlayerBat-y-low"></div>
</div></div></div><div class="chapter-content"><h2>Add the ball</h2><p>The next thing to add is the ball.  You do this in a very similar way
to how you added the player’s bat.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a <code>Ball</code> sprite to your project.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-sprite", "name": "Ball"}' data-slug="add-Ball-sprite"></div>
</div></div><p>And it needs a costume.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add the <code>yellow-ball.png</code> costume from Pytch’s media library to your
sprite.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-medialib-appearances-entry", "actor": {"kind": "sprite", "name": "Ball"}, "displayIdentifier": "yellow-ball.png", "nItems": 1}' data-slug="add-Ball-costume"></div>
</div></div><p>When the green flag is clicked, the ball should go to the very centre
of the court.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a “when green flag clicked” script to your <code>Ball</code> sprite, with
code to move it to the centre of the court.</p>
</div><div class="learner-task-help">
<p>The centre of the court is at coordinates <code>(0, 0)</code>.  You can check
this with the “Show coordinates” tool.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "codeText": "self.go_to_xy(0, 0)"}' data-slug="centre-Ball-on-green-flag"></div>
</div></div><p>Then it should straight away start moving away from the player, to
give them time to get ready.  This means moving to the right.</p><p>It’s useful to think ahead a bit here.  The ball won’t always be
moving to the right.  Once the robot has hit the ball, the ball will
move to the left.  To remember the direction the ball is travelling
in, you can use a <em>variable</em>.  Choosing a good name for variables is
important.  This variable will remember the <em>velocity</em> of the ball in
the <em>x</em> direction, so <code>x_velocity</code> is a good name.</p><p>(You might have thought of “speed” — the difference is that “velocity”
includes information about direction but “speed” doesn’t.)</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code which sets a variable <code>x_velocity</code> to the value <code>3</code>.  This
value seems about right to make the ball move at a good speed, but you
can experiment.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3"}' data-slug="define-Ball-x-velocity"></div>
</div></div><p>Now you can write code to move the ball.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a <code>while True</code> loop which moves the ball horizontally with the
correct velocity.</p>
</div><div class="learner-task-help">
<p>Moving the ball horizontally is done by changing its <em>x</em> coordinate by
the value of the <code>x_velocity</code> variable.</p>
</div><div class="learner-task-help">
<p>You will need the code</p>
<pre><code class="language-python">self.change_x(x_velocity)
</code></pre>
<p>inside a <code>while True</code> loop.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)"}' data-slug="move-Ball-with-x-velocity"></div>
</div></div><h3>Test it!</h3><div class="learner-task"><div class="learner-task-intro">
<p>Try your game.  You should still be able to move the player bat up and
down (<code>w</code> and <code>s</code> keys) while the ball moves to the right.</p>
<p><strong>There is a bug — what is it?</strong></p>
</div><div class="learner-task-help">
<p>The ball just keeps going to the right, all the way off the court.</p>
</div></div><p>The problem is that, because of the <code>while True</code>, the ball just keeps
going right, off the edge of the court.</p><p>The next chapter will add the robot bat for the player to play
against.  This will give the ball something to bounce off.</p></div><div class="chapter-content"><h2>Add the robot opponent</h2><p>Adding a sprite should be familiar by now!</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a <em>RobotBat</em> sprite to your program.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-sprite", "name": "RobotBat"}' data-slug="add-RobotBat-sprite"></div>
</div></div><p>There are some “Boing robot bat” costumes in the media library.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add the right costumes to this new sprite.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-medialib-appearances-entry", "actor": {"kind": "sprite", "name": "RobotBat"}, "displayIdentifier": "Boing robot bats", "nItems": 2}' data-slug="add-RobotBat-costumes"></div>
</div></div><p>At the start of the game, the robot bat needs to go to the correct
place on the screen.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a “when green flag script” to your <code>RobotBat</code> sprite, with code
which moves it to the correct starting point — at the right,
vertically centred.</p>
</div><div class="learner-task-help">
<p>The coordinates <code>(212, 0)</code> are a reasonable guess for this.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-script", "path": {"actor": {"kind": "sprite", "name": "RobotBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "codeText": "self.go_to_xy(212, 0)"}' data-slug="centre-RobotBat-on-green-flag"></div>
</div></div><p>The robot bat will need some intelligence, but next you’ll go back to
the <code>Ball</code> sprite, and make it bounce.</p></div><div class="chapter-content"><h2>Bounce the ball off the bats: simple version</h2><p>You’ll develop the “bounce off bats” code in stages.  To start with,
the ball will always bounce off the left and right edges, taking no
notice of where the bats are.</p><p>The ball can tell if it’s moved far enough to the right that it should
bounce off the robot.  It does this by looking at its <em>x</em> coordinate.
If it has moved too far, it needs to move <em>back</em> the same amount it just
moved, and then change its <code>x_velocity</code> to be the <em>opposite</em> of what
it just was.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code to the <code>Ball</code> which:</p>
<ul>
<li>Checks whether its <em>x</em> coordinate is greater than some fixed value;
  you can check that <code>195</code> works for this.</li>
<li>If so, you need to do two things:<ul>
<li>Change the ball’s <em>x</em> coordinate by the opposite (i.e., negative)
  of the <code>x_velocity</code>.  This puts the ball back where it was before
  it moved.</li>
<li>Set the <code>x_velocity</code> to the opposite of what it currently is.</li>
</ul>
</li>
</ul>
</div><div class="learner-task-help">
<p>You will need an <code>if</code> statement.  The test will be</p>
<pre><code class="language-python-expression">self.x_position &gt; 195
</code></pre>
</div><div class="learner-task-help">
<p>To find the negative of the value in the variable <code>x_velocity</code>, you
can use the Python expression</p>
<pre><code class="language-python-expression">-x_velocity
</code></pre>
<p>You can use this expression both to change the ball’s <em>x</em> coordinate,
and to update the value of the <code>x_velocity</code> variable.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity"}' data-slug="bounce-Ball-off-RobotBat"></div>
</div></div><p>You can do something very similar to make the ball bounce when it’s at
the left edge of the court — remember, at this point in making the
game, it doesn’t matter where the bat is.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code to the <code>Ball</code> which makes it bounce at the left edge.  The
code will be very similar to the three lines you just added.</p>
</div><div class="learner-task-help">
<p>The test in the <code>if</code> statement needs to check whether the ball is ‘too
far’ left, using the Python expression</p>
<pre><code class="language-python-expression">self.x_position &lt; -195
</code></pre>
</div><div class="learner-task-help">
<p>But the code “inside the <code>if</code>” to actually make the bounce happen is
exactly the same.</p>
<p>(You might be wondering whether we should combine these <code>if</code>
statements, if their bodies are the same.  We keep them separate
because we will soon need to do different things depending on whether
the ball has reached the player’s bat or the robot’s bat.)</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity"}' data-slug="bounce-Ball-off-PlayerBat"></div>
</div></div><h3>Test it!</h3><div class="learner-task"><div class="learner-task-intro">
<p>Try your game.  You should still be able to move the player bat up and
down (<code>w</code> and <code>s</code> keys).  The ball should bounce back and forth.</p>
<p><strong>There is a bug (which we were expecting) — what is it?</strong></p>
</div><div class="learner-task-help">
<p>The ball bounces even if the player misses it.</p>
</div></div><p>The problem is that the ball bounces even if the player’s bat is
nowhere near the ball.  The next chapter will fix this.</p></div><div class="chapter-content"><h2>Bounce properly off the player’s bat</h2><p>Once the code knows the ball is far enough left that it might bounce
off the player’s bat, it should then also check whether the ball is
touching the bat.</p><div class="learner-task"><div class="learner-task-intro">
<p>Move the “bounce at left” lines of code inside another <code>if</code> statement,
inside the</p>
<pre><code class="language-python">if self.x_position &lt; -195:
</code></pre>
<p>one.  The new <code>if</code> statement should test whether the ball is touching
the player bat.</p>
<p><strong>Why not use <code>and</code> like before?</strong>  Looking ahead, we want to do
something different if the ball is far enough left but the player
misses it.</p>
</div><div class="learner-task-help">
<p>The help bar will show you some examples of testing for one sprite
touching another.  Look for the Python equivalent of this Scratch
block:</p>
<pre><code class="language-scratch">&lt; touching [PlayerBat v] &gt;
</code></pre>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity"}' data-slug="check-hit-PlayerBat"></div>
</div></div><p>Now the ball bounces when it should.  If the player is too high or too
low, the ball carries on past, off to the left of the court.</p><p>But it’s not an interesting game because the ball only moves exactly
left and right.  The ball needs to bounce off in different directions.</p><p>To make this work, the ball <em>also</em> needs to remember how quickly it’s
moving <em>vertically</em>, i.e., in the <em>y</em> direction.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a variable <code>y_velocity</code> which will store how quickly (and in which
direction) the ball is moving in the <em>y</em> direction.  Think about what
its starting value should be.</p>
</div><div class="learner-task-help">
<p>The ball starts off moving exactly horizontally, so its <em>y</em>-velocity
should start at zero.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity"}' data-slug="add-Ball-state-y-velocity"></div>
</div></div><p>Now the code needs to <em>use</em> this variable.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code at the end of the “body” of the <code>while True</code> loop which
changes the ball’s <em>y</em> coordinate by its <code>y_velocity</code>.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n\n    self.change_y(y_velocity)"}' data-slug="change-Ball-y"></div>
</div></div><p>At the moment this makes no difference, because changing something by
zero leaves it alone.</p><div class="learner-task"><div class="learner-task-intro">
<p>Give the ball a random <code>y_velocity</code> when it bounces off the player’s
bat.</p>
</div><div class="learner-task-help">
<p>Good values for <code>y_velocity</code> are whole numbers from <code>-4</code> to <code>4</code>
(inclusive).  Look in the help to find out how to choose a random
number in this range.</p>
</div><div class="learner-task-help">
<p>The Python expression</p>
<pre><code class="language-python-expression">random.randint(-4, 4)
</code></pre>
<p>will do this.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n\n    self.change_y(y_velocity)", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n\n    self.change_y(y_velocity)"}' data-slug="random-Ball-y-velocity-PlayerBat-bounce"></div>
</div></div><p>The ball needs to do the same when it bounces off the robot bat.</p><div class="learner-task"><div class="learner-task-intro">
<p>Give the ball a random <code>y_velocity</code> when it bounces off the robot
bat.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n\n    self.change_y(y_velocity)", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n\n    self.change_y(y_velocity)"}' data-slug="random-Ball-y-velocity-RobotBat-bounce"></div>
</div></div><h3>Test it!</h3><div class="learner-task"><div class="learner-task-intro">
<p>Try your game.  You should still be able to move the player bat up and
down (<code>w</code> and <code>s</code> keys).  The ball should bounce back and forth, and
when the player hits it, it should go in a random direction.</p>
<p><strong>There is a bug — what is it?</strong></p>
</div><div class="learner-task-help">
<p>The ball goes off the top or bottom of the court.</p>
</div></div><p>If the ball goes off the bat at a steep enough angle, the ball goes
right off the top or bottom of the court.  The next chapter will fix
this.</p></div><div class="chapter-content"><h2>Bounce the ball off the top and bottom of the court</h2><p>This is a similar problem to bouncing the ball off a bat, except the
code needs to check the <em>y</em> coordinate, and work with the <code>y_velocity</code>
variable.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code after the <code>change_y()</code> code which makes the ball check if it
has gone too high or too low, and react correctly if so.</p>
</div><div class="learner-task-help">
<p>You can use an <code>if</code> statement with a test which asks whether either of
the following is true:</p>
<ul>
<li>the <em>y</em> coordinate is “too big” (meaning the ball has gone off the
  top of the court); greater than <code>150</code> counts as too big</li>
<li>the <em>y</em> coordinate is “too small” (meaning the ball has gone off the
  bottom of the court); smaller than <code>-150</code> counts as too small.</li>
</ul>
<p>You can join these individual tests with Python’s <code>or</code> operator,
because the behaviour in both cases is the same.</p>
</div><div class="learner-task-help">
<p>The test in your <code>if</code> statement will be</p>
<pre><code class="language-python-expression">self.y_position &gt; 150 or self.y_position &lt; -150
</code></pre>
</div><div class="learner-task-help">
<p>If the ball is too high or too low, you need code which:</p>
<ul>
<li>changes the ball’s <em>y</em> coordinate by the opposite of the change it
  just made;</li>
<li>makes the <code>y_velocity</code> be the opposite of what it currently is.</li>
</ul>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n\n    self.change_y(y_velocity)", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity"}' data-slug="make-Ball-bounce-vertically"></div>
</div></div><h3>Test it!</h3><div class="learner-task"><div class="learner-task-intro">
<p>Try your game.</p>
<p><strong>There are some bugs left — what are they?</strong></p>
</div><div class="learner-task-help">
<ul>
<li>The game is too generous about letting the player hit the ball — the
  player can “hit” the ball after it’s gone past the bat.</li>
<li>The ball can “get stuck” in the player’s bat.</li>
<li>The robot player never moves, but the ball bounces off the
  right-hand edge of the screen anyway.</li>
</ul>
</div></div><p>Click “Show me” to see what the bugs are.  The next chapters will fix
them.</p></div><div class="chapter-content"><h2>End the game if the player misses</h2><p>The code to bounce the ball off the player’s bat checked if the ball
was touching the bat, and bounced the ball if so.  But it needs to
also do something if the ball is <em>not</em> touching the bat — it needs to
end the game in this case.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add an <code>else</code> clause to the</p>
<pre><code class="language-python">if self.touching(PlayerBat):
    # [code to bounce ball]
</code></pre>
<p>statement, so that if the player misses, that's the end of the
game.</p>
</div><div class="learner-task-help">
<p>You can use the help to see how <code>if</code>/<code>else</code> statements work in Python.</p>
</div><div class="learner-task-help">
<p>The <code>else</code> code should make the ball hide, and use the Python <code>break</code>
statement to jump out of the <code>while True</code> loop and finish the game.</p>
</div><div class="learner-task-help">
<p>To learn how to make the ball hide, look in the help for the Python
version of the Scratch block</p>
<pre><code class="language-scratch">hide
</code></pre>
<p>This block is in the <em>Looks</em> section.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n        else:\n            self.hide()\n            break\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity"}' data-slug="hide-Ball-if-PlayerBat-misses"></div>
</div></div></div><div class="chapter-content"><h2>Move the robot’s bat automatically</h2><p>Returning to the robot player, at the moment it just goes to the
centre at the start of the game and stays there.  It needs to keep its
vertical position (<em>y</em> coordinate) matching the ball’s.  This
will make it follow the ball up and down.</p><h3>Find the ball's <em>y</em> coordinate</h3><p>Inside a <code>RobotBat</code> script, you can get the <em>y</em> coordinate of the
<code>RobotBat</code> with the Python expression</p><pre><code class="language-python-expression">self.y_position
</code></pre><p>The <code>self</code> means that it's the <code>RobotBat</code> itself whose
<em>y</em> coordinate you want.</p><p>To get a <em>different sprite's</em> <em>y</em> coordinate, you can use similar
code, but replacing <code>self</code> with an expression for the sprite whose
<em>y</em> coordinate you want.</p><p>An Python expression for "the Ball" is</p><pre><code class="language-python-expression">Ball.the_original()
</code></pre><p>This code talks about 'the original', because sprites can have
<em>clones</em>, and the code needs to say exactly which Ball you want.  The
details are beyond the scope of this tutorial, so don't worry too much
about this.</p><p>Putting this together, you can use the Python expression</p><pre><code class="language-python-expression">Ball.the_original().y_position
</code></pre><p>to find the <em>y</em> coordinate of the Ball in your game.</p><h3>Move the robot bat up or down to track the ball</h3><p>Now you’re ready to add code so the robot’s bat moves up and down to
track the ball.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code to the <code>RobotBat</code> sprite which makes it forever make its <em>y</em>
coordinate match the Ball’s.</p>
</div><div class="learner-task-help">
<p>You can use a <code>while True:</code> loop to make the <code>RobotBat</code> constantly
move.  The “body” of the loop should have code which moves the
<code>RobotBat</code> up or down to match the <code>Ball</code>.</p>
</div><div class="learner-task-help">
<p>To make your code easier to read, it is worth breaking the loop body
into two separate lines of code:</p>
<ul>
<li>Find the Ball's <em>y</em> coordinate and assign it to a variable; a
  good name for this variable might be <code>target_y</code>, because it is the
  <em>y</em> coordinate the <code>RobotBat</code> should aim for.</li>
<li>Set the <em>y</em> coordinate of the <code>RobotBat</code> to <code>target_y</code>.</li>
</ul>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "RobotBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(212, 0)", "newCodeText": "self.go_to_xy(212, 0)\n\nwhile True:\n    target_y = Ball.the_original().y_position\n    self.set_y(target_y)"}' data-slug="make-RobotBat-track-Ball"></div>
</div></div><p>This is much better, but still not quite right.  The robot can go off
the top of the court or off the bottom.</p><p>The problem is that <code>target_y</code> can be too big or too small.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code just before the <code>set_y()</code> call which tests whether <code>target_y</code>
is too big, and if so, sets it to the maximum allowed value.  “Too
big” means greater than <code>112</code>, the same value as we used to stop the
player’s bat going off the top of the court.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "RobotBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(212, 0)\n\nwhile True:\n    target_y = Ball.the_original().y_position\n    self.set_y(target_y)", "newCodeText": "self.go_to_xy(212, 0)\n\nwhile True:\n    target_y = Ball.the_original().y_position\n    if target_y &gt; 112:\n        target_y = 112\n    self.set_y(target_y)"}' data-slug="clamp-RobotBat-y-high"></div>
</div></div><p>Now if you test this, you should see that the robot bat stops at the
top of the court.  But it still goes off the bottom.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code just before the <code>set_y()</code> call which tests whether the
<code>target_y</code> is too small, and if so, sets it to the minimum allowed
value.  “Too small” means less than <code>-112</code>.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "RobotBat"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(212, 0)\n\nwhile True:\n    target_y = Ball.the_original().y_position\n    if target_y &gt; 112:\n        target_y = 112\n    self.set_y(target_y)", "newCodeText": "self.go_to_xy(212, 0)\n\nwhile True:\n    target_y = Ball.the_original().y_position\n    if target_y &gt; 112:\n        target_y = 112\n    if target_y &lt; -112:\n        target_y = -112\n    self.set_y(target_y)"}' data-slug="clamp-RobotBat-y-low"></div>
</div></div></div><div class="chapter-content"><h2>Add effects when a bat hits the ball</h2><p>The game would look better with an effect when the player or the
robots hits the ball.  This is what the costumes with “wince” in their
name are for.</p><h3>How sprites can communicate</h3><p>Pytch uses the same idea as Scratch to let one sprite tell another
sprite to do something.  A sprite can <em>broadcast a message</em>, and then
any other sprite (or even the same sprite) can <em>receive</em> that message
and run some Python code.</p><p>For example, if you’ve worked with Scratch, you might know that the
Scratch block</p><pre><code class="language-scratch">broadcast (jump-up-and-down v)
</code></pre><p>means that any Scratch code, in any sprite, under the hat block</p><pre><code class="language-scratch">when I receive [jump-up-and-down v]
</code></pre><p>will run.</p><p>In Pytch, you use the code</p><pre><code class="language-python">pytch.broadcast("jump-up-and-down")
</code></pre><p>to broadcast a message.</p><h3>Make the player’s bat react when hit</h3><p>You can use this in your game — the Ball can broadcast a message when
it bounces off the player’s bat, and the <code>PlayerBat</code> can run some code
when it receives that message.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a script <strong>to the <code>PlayerBat</code> sprite</strong> which runs when the sprite
receives a <code>"player-hit"</code> message, with code which:</p>
<ul>
<li>switches to the <code>"player-bat-wince.png"</code> costume;</li>
<li>waits a short time;</li>
<li>switches back to the <code>"player-bat-smile.png"</code> costume.</li>
</ul>
</div><div class="learner-task-help">
<p>To switch costume, you can either give the costume name, like</p>
<pre><code class="language-python">self.switch_costume("player-bat-wince.png")
# or
self.switch_costume("player-bat-smile.png")
</code></pre>
<p>or, because there are only two costumes, you can say</p>
<pre><code class="language-python">self.next_costume()
</code></pre>
<p>for both switches.  This works because if a sprite is wearing its last
costume, <code>self.next_costume()</code> moves back to the first costume.</p>
<p>Which way do you prefer?</p>
</div><div class="learner-task-help">
<p>To wait a short time, you can use the <code>pytch.wait_seconds()</code>
function.  You can wait for less than a whole second by using a
decimal fraction, such as <code>0.5</code> for half a second.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-script", "path": {"actor": {"kind": "sprite", "name": "PlayerBat"}, "methodName": "flash_briefly"}, "event": {"kind": "message-received", "message": "player-hit"}, "codeText": "self.switch_costume(\"player-bat-wince.png\")\npytch.wait_seconds(0.3)\nself.switch_costume(\"player-bat-smile.png\")"}' data-slug="define-PlayerBat-hit-handler"></div>
</div></div><p>To make this animation actually happen, the ball needs to broadcast
the <code>"player-hit"</code> message when it bounces off the player’s bat.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code <strong>to the <code>Ball</code> sprite</strong> which broadcasts the message as part
of the “bounce off player’s bat” section.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n        else:\n            self.hide()\n            break\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n            pytch.broadcast(\"player-hit\")\n        else:\n            self.hide()\n            break\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity"}' data-slug="trigger-PlayerBat-flash-on-hit"></div>
</div></div><h3>Make the robot’s bat react when hit</h3><p>You can do something very similar for the robot.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add a script <strong>to the <code>RobotBat</code> sprite</strong> which runs when the sprite
receives a <code>"robot-hit"</code> message, and which switches briefly to its
<code>"robot-bat-wince.png"</code> costume.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "add-script", "path": {"actor": {"kind": "sprite", "name": "RobotBat"}, "methodName": "flash_briefly"}, "event": {"kind": "message-received", "message": "robot-hit"}, "codeText": "self.switch_costume(\"robot-bat-wince.png\")\npytch.wait_seconds(0.3)\nself.switch_costume(\"robot-bat-smile.png\")"}' data-slug="define-RobotBat-hit-handler"></div>
</div></div><p>To make this actually happen, the ball must broadcast <code>"robot-hit"</code> at
the right time.</p><div class="learner-task"><div class="learner-task-intro">
<p>Add code <strong>to the <code>Ball</code> sprite</strong> which broadcasts the message as part
of the “bounce off robot’s bat” section.</p>
</div><div class="learner-task-help">
<div class="jr-commit" data-jr-commit='{"kind": "edit-script", "path": {"actor": {"kind": "sprite", "name": "Ball"}, "methodName": "play"}, "event": {"kind": "green-flag"}, "oldCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n            pytch.broadcast(\"player-hit\")\n        else:\n            self.hide()\n            break\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity", "newCodeText": "self.go_to_xy(0, 0)\n\nx_velocity = 3\ny_velocity = 0\nwhile True:\n    self.change_x(x_velocity)\n\n    if self.x_position &gt; 195:\n        self.change_x(-x_velocity)\n        x_velocity = -x_velocity\n        y_velocity = random.randint(-4, 4)\n        pytch.broadcast(\"robot-hit\")\n\n    if self.x_position &lt; -195:\n        if self.touching(PlayerBat):\n            self.change_x(-x_velocity)\n            x_velocity = -x_velocity\n            y_velocity = random.randint(-4, 4)\n            pytch.broadcast(\"player-hit\")\n        else:\n            self.hide()\n            break\n\n    self.change_y(y_velocity)\n\n    if self.y_position &gt; 150 or self.y_position &lt; -150:\n        self.change_y(-y_velocity)\n        y_velocity = -y_velocity"}' data-slug="trigger-RobotBat-flash-on-hit"></div>
</div></div><p>Congratulation!  The game is complete!</p></div><div class="chapter-content"><h2>Challenges</h2><p>Here are some ways you could make the game better.  Both of these
tasks are quite advanced, so your first step should be to think about
how to break the job down into manageable pieces.</p><ul>
<li>At the moment, the human player has no chance against the computer.
  Can you make it so the computer does <em>not</em> always win?</li>
<li>At the moment, the game stops once the player misses the ball.  Can
  you instead keep score, and make it so the winner is the first to
  get ten points?  This only makes sense if you’ve already made it so
  the computer sometimes misses!</li>
</ul><p>You could experiment with changing the physics of the game, for
example:</p><ul>
<li>Add gravity, so the ball falls towards the bottom of the screen.
  Think about how the <code>y_velocity</code> of the <code>Ball</code> sprite needs to
  change to give the right effect.  You might then also want to change
  the random velocity the ball gets when it bounces off a bat.</li>
</ul><p>You could give the player more control, to add some skill to the game:</p><ul>
<li>Instead of giving the ball a random <em>y</em>-velocity when it bounces off
  a bat, make it so the angle depends on where on the bat the ball
  hit.  For instance, the ball could go up if it hits near the top of
  the bat.</li>
</ul><p>Can you think of other changes or improvements?</p></div></div>